#pragma once
#include <zGraphicsConfig.hpp>
#include "../../Graphics/Color.hpp"
#include "../Texture/Texture2D.hpp"
#include "../Texture/Texture2DIOObject.hpp"
#include <Utility/HasFlag.hpp>
//OPENGL material model
namespace zzz{

const zuint MAT_DIF=0x0001;
const zuint MAT_AMB=0x0002;
const zuint MAT_SPE=0x0004;
const zuint MAT_EMI=0x0008;

const zuint MAT_AMBTEX=0x0010;
const zuint MAT_DIFTEX=0x0020;

const zuint MAT_BUMTEX=0x0100;

class ZGRAPHICS_CLASS Material : public HasFlags
{
public:
  Material();
  ~Material();

  void ApplyMaterial();
  void BindDiffuseTexture(GLenum bindto = GL_TEXTURE0);
  void UnbindDiffuseTexture();
  void BindAmbientTexture(GLenum bindto = GL_TEXTURE0);
  void UnbindAmbientTexture();

  Colorf diffuse_, ambient_, specular_, emission_;
  float shininess_;
  
  Texture2D ambientTex_;
  string ambientTexName_;

  Texture2D diffuseTex_;
  string diffuseTexName_;

  Texture2D bumpTex_;
  string bumpTexName_;
};

template<>
class IOObject<Material>
{
public:
  static const zint32 RF_HASFLAGS=999;

  static const zint32 RF_DIFFUSE=1;
  static const zint32 RF_AMBIENT=2;
  static const zint32 RF_SPECULAR=3;
  static const zint32 RF_EMISSION=4;
  static const zint32 RF_SHININESS=5;

  static const zint32 RF_AMBIENTTEX=10;
  static const zint32 RF_AMBIENTTEXIMG=12;

  static const zint32 RF_DIFFUSETEX=20;
  static const zint32 RF_DIFFUSETEXIMG=22;

  static const zint32 RF_BUMPTEX=30;
  static const zint32 RF_BUMPTEXIMG=32;
  static void WriteFileR(RecordFile &fp, const zint32 label, const Material& src) {
    fp.WriteChildBegin(label);
    IOObject<HasFlags>::WriteFileR(fp, RF_HASFLAGS, src);
    if (src.HasFlag(MAT_DIF)) IOObj::WriteFileR(fp, RF_DIFFUSE, src.diffuse_);
    if (src.HasFlag(MAT_AMB)) IOObj::WriteFileR(fp, RF_AMBIENT, src.ambient_);
    if (src.HasFlag(MAT_SPE)) {
      IOObj::WriteFileR(fp, RF_SPECULAR, src.specular_);
      IOObj::WriteFileR(fp, RF_SHININESS, src.shininess_);
    }
    if (src.HasFlag(MAT_EMI)) IOObj::WriteFileR(fp, RF_EMISSION, src.emission_);
    if (src.HasFlag(MAT_AMBTEX)) {
      if (!src.ambientTexName_.empty()) {
        Image3uc img;
        img.LoadFile(src.ambientTexName_.c_str());
        IOObj::WriteFileR(fp, RF_AMBIENTTEXIMG, img);
      } else {
        IOObj::WriteFileR(fp, RF_AMBIENTTEX, src.ambientTex_);
      }
    }
    if (src.HasFlag(MAT_DIFTEX)) {
      if (!src.diffuseTexName_.empty()) {
        Image3uc img;
        img.LoadFile(src.diffuseTexName_.c_str());
        IOObj::WriteFileR(fp, RF_DIFFUSETEXIMG, img);
      } else {
        IOObj::WriteFileR(fp, RF_DIFFUSETEX, src.diffuseTex_);
      }
    }
    if (src.HasFlag(MAT_BUMTEX)) {
      if (!src.bumpTexName_.empty()) {
        Image3f img;
        img.LoadFile(src.bumpTexName_.c_str());
        IOObj::WriteFileR(fp, RF_BUMPTEXIMG, img);
      } else {
        IOObj::WriteFileR(fp, RF_BUMPTEX, src.bumpTex_);
      }
    }
    fp.WriteChildEnd();
  }
  static void ReadFileR(RecordFile &fp, const zint32 label, Material& dst) {
    fp.ReadChildBegin(label);
    IOObject<HasFlags>::ReadFileR(fp, RF_HASFLAGS, dst);
    if (dst.HasFlag(MAT_DIF)) IOObj::ReadFileR(fp, RF_DIFFUSE, dst.diffuse_);
    if (dst.HasFlag(MAT_AMB)) IOObj::ReadFileR(fp, RF_AMBIENT, dst.ambient_);
    if (dst.HasFlag(MAT_SPE)) {
      IOObj::ReadFileR(fp, RF_SPECULAR, dst.specular_);
      IOObj::ReadFileR(fp, RF_SHININESS, dst.shininess_);
    }
    if (dst.HasFlag(MAT_EMI)) IOObj::ReadFileR(fp, RF_EMISSION, dst.emission_);
    if (dst.HasFlag(MAT_AMBTEX)) {
      if (fp.LabelExist(RF_AMBIENTTEXIMG) && Context::current_context_) {
        Image3uc img;
        IOObj::ReadFileR(fp, RF_AMBIENTTEXIMG, img);
        dst.ambientTex_.ImageToTexture(img);
      } else if (fp.LabelExist(RF_AMBIENTTEX) && Context::current_context_)
        IOObj::ReadFileR(fp, RF_AMBIENTTEX, dst.ambientTex_);
    }
    if (dst.HasFlag(MAT_DIFTEX)) {
      if (fp.LabelExist(RF_DIFFUSETEXIMG) && Context::current_context_) {
        Image3uc img;
        IOObj::ReadFileR(fp, RF_DIFFUSETEXIMG, img);
        dst.diffuseTex_.ImageToTexture(img);
      } else if (fp.LabelExist(RF_DIFFUSETEX) && Context::current_context_)
        IOObj::ReadFileR(fp, RF_DIFFUSETEX, dst.diffuseTex_);
    }
    if (dst.HasFlag(MAT_BUMTEX)) {
      if (fp.LabelExist(RF_BUMPTEXIMG) && Context::current_context_) {
        Image3f img;
        IOObj::ReadFileR(fp, RF_BUMPTEXIMG, img);
        dst.bumpTex_.ImageToTexture(img);
      } else if (fp.LabelExist(RF_BUMPTEX) && Context::current_context_)
        IOObj::ReadFileR(fp, RF_BUMPTEX, dst.bumpTex_);
    }
    fp.ReadChildEnd();
  }
};
}
